﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
using LiveWebServiceBase;
using LiveWebServiceBase.ReturnedTypes;
using LiveWebServiceBase.ServiceUser;
using LiveWebServiceBase.ServiceUserSettings;
using Microsoft.Exchange.WebServices.Data;
using System.Web.Caching;

namespace LiveWebService.EWSModule
{
    public class LiveEWS
    {
        #region Private Variables
        private static object objLock = new object();
        private int urlscounter;
        private string ewsAdminLogin;
        private string ewsAdminPass;
        private ExchangeService service;
        #endregion

        #region Public Variables
        public string CurrnetServerUrl
        {
            get
            {
                try
                {
                    return ((Uri)System.Web.HttpContext.Current.Cache[ewsAdminLogin]).Host;
                }
                catch
                {
                    return "none";
                }
            }
        }
        #endregion

        public LiveEWS(User currentUser, string LiveID)
        {
            //try
            {
                Account aItem = currentUser.GetAccountByLiveID(LiveID);

                ewsAdminLogin = aItem.ewsAdm;
                ewsAdminPass = aItem.ewsAdmPwd;

                string currentCacheKey = currentUser.UserName + "_" + aItem.ewsAdm.Split('@')[0] + "_EWS";

                lock (objLock)
                {
                    if (System.Web.HttpContext.Current.Cache[currentCacheKey] == null)
                    {
                        service = new ExchangeService(ExchangeVersion.Exchange2010);
                        service.Credentials = new WebCredentials(ewsAdminLogin, ewsAdminPass);
                        service.PreAuthenticate = true;

                        if (System.Web.HttpContext.Current.Cache[ewsAdminLogin] == null)
                        {
                            urlscounter = Settings.EWSVariables.GetCountServiceURLs();
                            CheckConnection(ewsAdminLogin);
                        }
                        else
                        {
                            service.Url = (Uri)System.Web.HttpContext.Current.Cache[ewsAdminLogin];
                        }

                        System.Web.HttpContext.Current.Cache.Insert(currentCacheKey, service, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(20), CacheItemPriority.NotRemovable, null);
                    }
                    else
                    {
                        service = (ExchangeService)System.Web.HttpContext.Current.Cache[currentCacheKey];
                    }

                }
            }
        }

        #region Private Functions
        private void CheckConnection(string userlogin)
        {
            try
            {
                if (urlscounter > 0)
                {
                    string url = Settings.EWSVariables.GetServiceURL(urlscounter--);
                    service.Url = new Uri(url);

                    GetImpersonation(userlogin);
                    //Microsoft.Exchange.WebServices.Data.Appointment.Bind(Bind(service, WellKnownFolderName.Inbox);
                    service.ResolveName("administrator");

                    System.Web.HttpContext.Current.Cache.Insert(userlogin, service.Url, null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(1), CacheItemPriority.NotRemovable, null);
                }
                else if (urlscounter == 0)
                {
                    urlscounter--;
                    service.AutodiscoverUrl(userlogin, delegate(string str) { return true; });
                    System.Web.HttpContext.Current.Cache.Insert(userlogin, service.Url, null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(1), CacheItemPriority.NotRemovable, null);
                }
                else
                    throw new Exception("All service urls are tryed.");
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("All service urls are tryed."))
                    throw new Exception("Error with Live Exchange, last url", ex);
                else if (ex.Message.Contains("Autodiscover"))
                    throw new Exception("Autodiscover error", ex);
                else if (ex.Message.Contains("not have permission to impersonate"))
                    throw ex;
                else
                    CheckConnection(userlogin);
            }
        }

        private void GetImpersonation(string userLogin)
        {
            service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, userLogin);
            service.PreAuthenticate = true;
        }

        private PropertyDefinition GetItemSchema(ContactParameterType type)
        {
            switch (type)
            {
                case ContactParameterType.Birthday:
                    return ContactSchema.Birthday;
                case ContactParameterType.BusinessHomePage:
                    return ContactSchema.BusinessHomePage;
                case ContactParameterType.Children:
                    return ContactSchema.Children;
                case ContactParameterType.Companies:
                    return ContactSchema.Companies;
                case ContactParameterType.CompanyName:
                    return ContactSchema.CompanyName;
                case ContactParameterType.ImAddress1:
                    return ContactSchema.ImAddresses;
                case ContactParameterType.ImAddress2:
                    return ContactSchema.ImAddresses;
                case ContactParameterType.ImAddress3:
                    return ContactSchema.ImAddresses;
                case ContactParameterType.PhoneNumberAssistantPhone:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberBusinessFax:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberBusinessPhone:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberBusinessPhone2:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberCallback:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberCarPhone:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberCompanyMainPhone:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberHomeFax:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberHomePhone:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberHomePhone2:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberIsdn:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberMobilePhone:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberOtherFax:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberOtherTelephone:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberPager:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberPrimaryPhone:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberRadioPhone:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberTelex:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhoneNumberTtyTddPhone:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhysicalAddressesBusiness:
                    return ContactSchema.PhysicalAddresses;
                case ContactParameterType.PhysicalAddressesHome:
                    return ContactSchema.PhysicalAddresses;
                case ContactParameterType.PhysicalAddressesOther:
                    return ContactSchema.PhysicalAddresses;
                case ContactParameterType.ContactSource:
                    return ContactSchema.ContactSource;
                case ContactParameterType.Department:
                    return ContactSchema.Department;
                case ContactParameterType.DisplayName:
                    return ContactSchema.DisplayName;
                case ContactParameterType.EmailAddressDictionary:
                    return ContactSchema.EmailAddresses;
                case ContactParameterType.FileAs:
                    return ContactSchema.FileAs;
                case ContactParameterType.FileAsMapping:
                    return ContactSchema.FileAsMapping;
                case ContactParameterType.Generation:
                    return ContactSchema.Generation;
                case ContactParameterType.GivenName:
                    return ContactSchema.GivenName;
                case ContactParameterType.HasPicture:
                    return ContactSchema.HasPicture;
                case ContactParameterType.ImAddressDictionary:
                    return ContactSchema.ImAddresses;
                case ContactParameterType.Initials:
                    return ContactSchema.Initials;
                case ContactParameterType.JobTitle:
                    return ContactSchema.JobTitle;
                case ContactParameterType.Manager:
                    return ContactSchema.Manager;
                case ContactParameterType.MiddleName:
                    return ContactSchema.MiddleName;
                case ContactParameterType.Mileage:
                    return ContactSchema.Mileage;
                case ContactParameterType.NickName:
                    return ContactSchema.NickName;
                case ContactParameterType.OfficeLocation:
                    return ContactSchema.OfficeLocation;
                case ContactParameterType.PhoneNumberDictionary:
                    return ContactSchema.PhoneNumbers;
                case ContactParameterType.PhysicalAddressIndex:
                    return ContactSchema.PostalAddressIndex;
                case ContactParameterType.Profession:
                    return ContactSchema.Profession;
                case ContactParameterType.SpouseName:
                    return ContactSchema.SpouseName;
                case ContactParameterType.Surname:
                    return ContactSchema.Surname;
                case ContactParameterType.WeddingAnniversary:
                    return ContactSchema.WeddingAnniversary;
                default:
                    return null;
            }
        }

        private PropertyDefinition GetItemSchema(FolderSearchParameterType type)
        {
            switch (type)
            {
                case FolderSearchParameterType.ChildFolderCount:
                    return FolderSchema.ChildFolderCount;
                case FolderSearchParameterType.DisplayName:
                    return FolderSchema.DisplayName;
                case FolderSearchParameterType.EffectiveRights:
                    return FolderSchema.EffectiveRights;
                case FolderSearchParameterType.FolderClass:
                    return FolderSchema.FolderClass;
                case FolderSearchParameterType.ManagedFolderInformation:
                    return FolderSchema.ManagedFolderInformation;
                case FolderSearchParameterType.Permissions:
                    return FolderSchema.Permissions;
                case FolderSearchParameterType.TotalCount:
                    return FolderSchema.TotalCount;
                case FolderSearchParameterType.UnreadCount:
                    return FolderSchema.UnreadCount;
                default:
                    return null;
            }
        }

        private PropertyDefinition GetItemSchema(MailSearchParameterType type)
        {
            switch (type)
            {
                case MailSearchParameterType.AllowedResponseActions:
                    return ItemSchema.AllowedResponseActions;
                case MailSearchParameterType.Attachments:
                    return ItemSchema.Attachments;
                case MailSearchParameterType.Body:
                    return ItemSchema.Body;
                case MailSearchParameterType.Categories:
                    return ItemSchema.Categories;
                case MailSearchParameterType.ConversationId:
                    return ItemSchema.ConversationId;
                case MailSearchParameterType.Culture:
                    return ItemSchema.Culture;
                case MailSearchParameterType.DateTimeCreated:
                    return ItemSchema.DateTimeCreated;
                case MailSearchParameterType.DateTimeReceived:
                    return ItemSchema.DateTimeReceived;
                case MailSearchParameterType.DateTimeSent:
                    return ItemSchema.DateTimeSent;
                case MailSearchParameterType.DisplayCc:
                    return ItemSchema.DisplayCc;
                case MailSearchParameterType.DisplayTo:
                    return ItemSchema.DisplayTo;
                case MailSearchParameterType.EffectiveRights:
                    return ItemSchema.EffectiveRights;
                case MailSearchParameterType.HasAttachments:
                    return ItemSchema.HasAttachments;
                case MailSearchParameterType.Id:
                    return ItemSchema.Id;
                case MailSearchParameterType.Importance:
                    return ItemSchema.Importance;
                case MailSearchParameterType.InReplyTo:
                    return ItemSchema.InReplyTo;
                case MailSearchParameterType.InternetMessageHeaders:
                    return ItemSchema.InternetMessageHeaders;
                case MailSearchParameterType.IsAssociated:
                    return ItemSchema.IsAssociated;
                case MailSearchParameterType.IsDraft:
                    return ItemSchema.IsDraft;
                case MailSearchParameterType.IsFromMe:
                    return ItemSchema.IsFromMe;
                case MailSearchParameterType.IsReminderSet:
                    return ItemSchema.IsReminderSet;
                case MailSearchParameterType.IsResend:
                    return ItemSchema.IsResend;
                case MailSearchParameterType.IsSubmitted:
                    return ItemSchema.IsSubmitted;
                case MailSearchParameterType.IsUnmodified:
                    return ItemSchema.IsUnmodified;
                case MailSearchParameterType.ItemClass:
                    return ItemSchema.ItemClass;
                case MailSearchParameterType.LastModifiedName:
                    return ItemSchema.LastModifiedName;
                case MailSearchParameterType.LastModifiedTime:
                    return ItemSchema.LastModifiedTime;
                case MailSearchParameterType.MimeContent:
                    return ItemSchema.MimeContent;
                case MailSearchParameterType.ParentFolderId:
                    return ItemSchema.ParentFolderId;
                case MailSearchParameterType.ReminderDueBy:
                    return ItemSchema.ReminderDueBy;
                case MailSearchParameterType.ReminderMinutesBeforeStart:
                    return ItemSchema.ReminderMinutesBeforeStart;
                case MailSearchParameterType.Sensitivity:
                    return ItemSchema.Sensitivity;
                case MailSearchParameterType.Size:
                    return ItemSchema.Size;
                case MailSearchParameterType.Subject:
                    return ItemSchema.Subject;
                case MailSearchParameterType.UniqueBody:
                    return ItemSchema.UniqueBody;
                case MailSearchParameterType.WebClientEditFormQueryString:
                    return ItemSchema.WebClientEditFormQueryString;
                case MailSearchParameterType.WebClientReadFormQueryString:
                    return ItemSchema.WebClientReadFormQueryString;
                default:
                    return null;
            }
        }

        private void AddPhysicalAddressPair(List<Pair> lstPair, PhysicalAddressDictionary PhysicalAddressDictionary, PhysicalAddressKey PhysicalAddressKey)
        {
            Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry adr;
            PhysicalAddressDictionary.TryGetValue(PhysicalAddressKey, out adr);

            if (adr != null)
            {
                LiveWebServiceBase.ReturnedTypes.PhysicalAddressEntry retVal = new LiveWebServiceBase.ReturnedTypes.PhysicalAddressEntry();
                retVal.City = adr.City;
                retVal.CountryOrRegion = adr.CountryOrRegion;
                retVal.PostalCode = adr.PostalCode;
                retVal.State = adr.State;
                retVal.Street = adr.Street;

                lstPair.Add(new Pair(PhysicalAddressKey, retVal));
            }
        }

        private void AddPhonePair(List<Pair> lstPair, PhoneNumberDictionary phoneDictionary, PhoneNumberKey phoneKey)
        {
            String str;
            phoneDictionary.TryGetValue(phoneKey, out str);

            if (str != null)
                lstPair.Add(new Pair(phoneKey, str));
        }

        private void AddImAddressPair(List<Pair> lstPair, ImAddressDictionary ImAddressDictionary, ImAddressKey ImAddressKey)
        {
            String str;
            ImAddressDictionary.TryGetValue(ImAddressKey, out str);

            if (str != null)
                lstPair.Add(new Pair(ImAddressKey, str));
        }

        private void AddEmailPair(List<Pair> lstPair, EmailAddressDictionary emailDictionary, EmailAddressKey emailKey)
        {
            EmailAddress adr;
            emailDictionary.TryGetValue(emailKey, out adr);

            if (adr != null)
            {
                LiveWebServiceBase.ReturnedTypes.EmailAddressEntry retVal = new LiveWebServiceBase.ReturnedTypes.EmailAddressEntry();
                retVal.Address = adr.Address;
                retVal.MailboxType = adr.MailboxType;
                retVal.Name = adr.Name;
                retVal.RoutingType = adr.RoutingType;

                lstPair.Add(new Pair(emailKey, retVal));
            }
        }

        private LiveWebServiceBase.ReturnedTypes.Contact ConvertContact(Microsoft.Exchange.WebServices.Data.Contact contact)
        {
            LiveWebServiceBase.ReturnedTypes.Contact retValue = new LiveWebServiceBase.ReturnedTypes.Contact();

            foreach (var property in retValue.GetType().GetProperties())
            {
                try
                {
                    Type conPropType;
                    if (contact.GetType().GetProperty(property.Name).PropertyType.ToString().Contains("DateTime"))
                        conPropType = contact.GetType().GetProperty(property.Name).PropertyType.GetGenericArguments()[0];
                    else
                        conPropType = contact.GetType().GetProperty(property.Name).PropertyType;

                    Type retPropType = property.PropertyType;
                    object contPropValue = contact.GetType().GetProperty(property.Name).GetValue(contact, null);


                    if (conPropType.Name.Contains("ItemId"))
                        property.SetValue(retValue, contPropValue.ToString(), null);
                    else if (conPropType.Name.Contains("Dictionary"))
                    {
                        #region EmailAddressDictionary
                        if (conPropType.Name.Contains("Email"))
                        {
                            List<Pair> lst = new List<Pair>();

                            AddEmailPair(lst, contPropValue as EmailAddressDictionary, EmailAddressKey.EmailAddress1);
                            AddEmailPair(lst, contPropValue as EmailAddressDictionary, EmailAddressKey.EmailAddress2);
                            AddEmailPair(lst, contPropValue as EmailAddressDictionary, EmailAddressKey.EmailAddress3);

                            property.SetValue(retValue, lst, null);
                        }
                        #endregion

                        #region ImAddressDictionary
                        else if (conPropType.Name.Contains("ImAddress"))
                        {
                            List<Pair> lst = new List<Pair>();

                            AddImAddressPair(lst, contPropValue as ImAddressDictionary, ImAddressKey.ImAddress1);
                            AddImAddressPair(lst, contPropValue as ImAddressDictionary, ImAddressKey.ImAddress2);
                            AddImAddressPair(lst, contPropValue as ImAddressDictionary, ImAddressKey.ImAddress3);

                            property.SetValue(retValue, lst, null);
                        }
                        #endregion

                        #region PhoneNumberDictionary
                        else if (conPropType.Name.Contains("PhoneNumber"))
                        {
                            List<Pair> lst = new List<Pair>();

                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.AssistantPhone);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.BusinessFax);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.BusinessPhone);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.BusinessPhone2);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.Callback);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.CarPhone);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.CompanyMainPhone);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.HomeFax);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.HomePhone);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.HomePhone2);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.Isdn);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.MobilePhone);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.OtherFax);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.OtherTelephone);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.Pager);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.PrimaryPhone);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.RadioPhone);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.Telex);
                            AddPhonePair(lst, contPropValue as PhoneNumberDictionary, PhoneNumberKey.TtyTddPhone);

                            property.SetValue(retValue, lst, null);
                        }
                        #endregion

                        #region PhysicalAddressDictionary
                        if (conPropType.Name.Contains("PhysicalAddress"))
                        {
                            List<Pair> lst = new List<Pair>();

                            AddPhysicalAddressPair(lst, contPropValue as PhysicalAddressDictionary, PhysicalAddressKey.Business);
                            AddPhysicalAddressPair(lst, contPropValue as PhysicalAddressDictionary, PhysicalAddressKey.Home);
                            AddPhysicalAddressPair(lst, contPropValue as PhysicalAddressDictionary, PhysicalAddressKey.Other);

                            property.SetValue(retValue, lst, null);
                        }
                        #endregion
                    }
                    else
                        property.SetValue(retValue, Convert.ChangeType(contPropValue, retPropType), null);
                }
                catch (Exception ex)
                {
                    string exmsg = ex.Message;
                }
            }
            return retValue;
        }

        private LiveWebServiceBase.ReturnedTypes.Folder ConvertFolder(Microsoft.Exchange.WebServices.Data.Folder folder)
        {
            LiveWebServiceBase.ReturnedTypes.Folder retVal = new LiveWebServiceBase.ReturnedTypes.Folder();

            retVal.ChildFolderCount = folder.ChildFolderCount;
            retVal.DisplayName = folder.DisplayName;
            retVal.FolderClass = folder.FolderClass;
            retVal.Id = folder.Id.UniqueId;
            retVal.TotalCount = folder.TotalCount;
            retVal.UnreadCount = folder.UnreadCount;

            return retVal;
        }

        //private List<LiveWebServiceBase.ReturnedTypes.Folder> GetFoldersByNames(List<string> lstFolderNames)
        //{
        //    List<LiveWebServiceBase.ReturnedTypes.Folder> retval = new List<LiveWebServiceBase.ReturnedTypes.Folder>();

        //    FolderView view = new FolderView(100);
        //    view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
        //    view.PropertySet.Add(FolderSchema.DisplayName);
        //    view.PropertySet.Add(FolderSchema.FolderClass);
        //    view.PropertySet.Add(FolderSchema.ChildFolderCount);
        //    view.PropertySet.Add(FolderSchema.TotalCount);
        //    view.PropertySet.Add(FolderSchema.UnreadCount);
        //    view.Traversal = FolderTraversal.Deep;

        //    List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
        //    foreach (var item in lstFolderNames)
        //        searchFilterCollection.Add(new SearchFilter.ContainsSubstring(FolderSchema.DisplayName, item));
        //    SearchFilter sFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchFilterCollection.ToArray());

        //    FindFoldersResults findFolderResults;

        //    if (lstFolderNames.Count > 0)
        //        findFolderResults = service.FindFolders(WellKnownFolderName.Root, sFilter, view);
        //    else
        //        findFolderResults = service.FindFolders(WellKnownFolderName.Root, view);

        //    foreach (var item in findFolderResults)
        //        if (item is Microsoft.Exchange.WebServices.Data.Folder && item.FolderClass != null && item.FolderClass == "IPF.Note" && item.DisplayName != "Unread Mail")
        //            retval.Add(this.ConvertFolder(item));

        //    return retval;
        //}

        private List<Microsoft.Exchange.WebServices.Data.Folder> GetFoldersByNames(List<string> lstFolderNames)
        {
            List<Microsoft.Exchange.WebServices.Data.Folder> retval = new List<Microsoft.Exchange.WebServices.Data.Folder>();

            List<string> lstNotWLKNFolderNames = new List<string>();

            foreach (string folderNameItem in lstFolderNames)
            {
                WellKnownFolderName? tmp = ConvertToWKFN(folderNameItem);

                if (tmp.HasValue)
                {
                    retval.Add(Microsoft.Exchange.WebServices.Data.Folder.Bind(service, tmp.Value));
                }
                else if (!string.IsNullOrWhiteSpace(folderNameItem))
                    lstNotWLKNFolderNames.Add(folderNameItem);
            }


            if (lstNotWLKNFolderNames.Count > 0)
            {
                FolderView view = new FolderView(100);
                view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
                view.PropertySet.Add(FolderSchema.DisplayName);
                view.PropertySet.Add(FolderSchema.FolderClass);
                view.PropertySet.Add(FolderSchema.ChildFolderCount);
                view.PropertySet.Add(FolderSchema.TotalCount);
                view.PropertySet.Add(FolderSchema.UnreadCount);
                view.PropertySet.Add(FolderSchema.ManagedFolderInformation);
                view.Traversal = FolderTraversal.Deep;

                List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
                foreach (var item in lstFolderNames)
                    searchFilterCollection.Add(new SearchFilter.ContainsSubstring(FolderSchema.DisplayName, item));
                SearchFilter sFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchFilterCollection.ToArray());

                FindFoldersResults findFolderResults;

                findFolderResults = service.FindFolders(WellKnownFolderName.Root, sFilter, view);

                foreach (var item in findFolderResults)
                    if ((item is Microsoft.Exchange.WebServices.Data.Folder || item is CalendarFolder) && !(item is SearchFolder))
                        retval.Add(item);
            }

            return retval;
        }

        private List<Microsoft.Exchange.WebServices.Data.Folder> GetAllFolders()
        {
            List<Microsoft.Exchange.WebServices.Data.Folder> lstResult = new List<Microsoft.Exchange.WebServices.Data.Folder>();

            FolderView view = new FolderView(100);
            view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
            view.PropertySet.Add(FolderSchema.DisplayName);
            view.PropertySet.Add(FolderSchema.FolderClass);
            view.PropertySet.Add(FolderSchema.ChildFolderCount);
            view.PropertySet.Add(FolderSchema.TotalCount);
            view.PropertySet.Add(FolderSchema.UnreadCount);
            view.Traversal = FolderTraversal.Deep;

            FindFoldersResults findFolderResults = service.FindFolders(WellKnownFolderName.Root, view);

            var tmp = GetFoldersByNames(new List<string> { });

            foreach (var item in findFolderResults)
                if (item is Microsoft.Exchange.WebServices.Data.Folder && item.FolderClass != null && item.FolderClass == "IPF.Note" && item.DisplayName != "Unread Mail")
                    lstResult.Add(item);

            return lstResult;
        }

        private WellKnownFolderName ConvertToWKFN(string foldername)
        {
            if (foldername.ToLower() == "calendar")
                return WellKnownFolderName.Calendar;
            else if (foldername.ToLower() == "contacts")
                return WellKnownFolderName.Contacts;
            else if (foldername.ToLower() == "deleteditems")
                return WellKnownFolderName.DeletedItems;
            else if (foldername.ToLower() == "drafts")
                return WellKnownFolderName.Drafts;
            else if (foldername.ToLower() == "inbox")
                return WellKnownFolderName.Inbox;
            else if (foldername.ToLower() == "journal")
                return WellKnownFolderName.Journal;
            else if (foldername.ToLower() == "junkemail")
                return WellKnownFolderName.JunkEmail;
            else if (foldername.ToLower() == "msgfolderroot")
                return WellKnownFolderName.MsgFolderRoot;
            else if (foldername.ToLower() == "notes")
                return WellKnownFolderName.Notes;
            else if (foldername.ToLower() == "outboox")
                return WellKnownFolderName.Outbox;
            else if (foldername.ToLower() == "publicfoldersroot")
                return WellKnownFolderName.PublicFoldersRoot;
            else if (foldername.ToLower() == "root")
                return WellKnownFolderName.Root;
            else if (foldername.ToLower() == "searchfolders")
                return WellKnownFolderName.SearchFolders;
            else if (foldername.ToLower() == "sentitems")
                return WellKnownFolderName.SentItems;
            else if (foldername.ToLower() == "tasks")
                return WellKnownFolderName.Tasks;
            else if (foldername.ToLower() == "voicemail")
                return WellKnownFolderName.VoiceMail;

            return WellKnownFolderName.Root;
        }
        #endregion

        #region Mails
        public KeyValuePair<int, int> GetLettersCount(string userLogin)
        {
            try
            {
                GetImpersonation(userLogin);

                Microsoft.Exchange.WebServices.Data.Folder inbox = Microsoft.Exchange.WebServices.Data.Folder.Bind(service, WellKnownFolderName.Inbox);

                return new KeyValuePair<int, int>(inbox.TotalCount, inbox.UnreadCount);
            }
            catch
            {
                return new KeyValuePair<int, int>();
            }
        }

        public KeyValuePair<int, int> GetLettersCount(string userLogin, List<string> folderName)
        {
            GetImpersonation(userLogin);

            int All = 0;
            int Unread = 0;

            foreach (Microsoft.Exchange.WebServices.Data.Folder folder in GetFoldersByNames(folderName))
                try
                {
                    All += folder.TotalCount;
                    Unread += folder.UnreadCount;
                }
                catch { }

            return new KeyValuePair<int, int>(All, Unread);
        }

        public List<MailboxInfo> GetLettersCount(List<string> userLogins)
        {
            List<MailboxInfo> result = new List<MailboxInfo>();
            foreach (string item in userLogins)
                try
                {
                    GetImpersonation(item);
                    var tmp = GetLettersCount(item);
                    result.Add(new MailboxInfo()
                    {
                        all = tmp.Key,
                        unread = tmp.Value,
                        email = item
                    });
                }
                catch { }

            return result;
        }

        public MailMessage GetMailMessage(string userLogin, string id, bool getattachment = false)
        {
            GetImpersonation(userLogin);
            MailMessage mm = new MailMessage();
            EmailMessage mes = EmailMessage.Bind(service, new ItemId(id));
            mm.id = mes.Id.UniqueId;
            mm.subject = mes.Subject;
            mm.body = mes.Body;

            if (getattachment)
            {
                mm.attachments = new List<MailAttachment>();
                foreach (var maitem in mes.Attachments)
                {
                    if (maitem is FileAttachment)
                    {
                        FileAttachment fileAttachment = maitem as FileAttachment;
                        fileAttachment.Load();

                        MailAttachment ma = new MailAttachment();
                        ma.contenttype = fileAttachment.ContentType;
                        ma.content = fileAttachment.Content;
                        ma.filename = fileAttachment.Name;

                        mm.attachments.Add(ma);
                    }
                }
            }

            if (mes.From != null)
                mm.from = mes.From.Name;
            foreach (var eaItem in mes.ToRecipients)
            {
                mm.to += eaItem.Name + ";";
            }

            if (mes.From != null)
                mm.fromEmail = mes.From.Address;
            foreach (var eaItem in mes.ToRecipients)
            {
                mm.to += eaItem.Address + ";";
            }

            mm.dateSent = mes.DateTimeSent;
            mm.dateRecieved = mes.DateTimeReceived;

            mm.isRead = mes.IsRead;

            mes.IsRead = true;
            mes.Update(ConflictResolutionMode.AlwaysOverwrite);

            return mm;
        }

        public List<MailMessage> MessageSearch(string userLogin, List<MailSearchParameter> parameters, List<string> foldersNames)
        {
            GetImpersonation(userLogin);
            List<MailMessage> mmList = new List<MailMessage>();
            List<SearchFilter> searchFilterCollection = new List<SearchFilter>();

            foreach (var item in parameters)
            {
                if (!string.IsNullOrEmpty(item.value))
                    searchFilterCollection.Add(new SearchFilter.IsEqualTo(GetItemSchema(item.type), item.value));
            }

            SearchFilter sFilter = null;

            if (searchFilterCollection.Count > 0)
                sFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchFilterCollection.ToArray());

            ItemView view = new ItemView(100);
            view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, ItemSchema.DateTimeReceived);
            view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);

            foreach (Microsoft.Exchange.WebServices.Data.Folder folder in GetFoldersByNames(foldersNames))
            {
                FindItemsResults<Item> findResults;

                if (sFilter == null)
                    findResults = service.FindItems(folder.Id, view);
                else
                    findResults = service.FindItems(folder.Id, sFilter, view);

                foreach (Item item in findResults.Items)
                {
                    if (item is EmailMessage)
                    {
                        try
                        {
                            MailMessage mm = new MailMessage();
                            EmailMessage mes = EmailMessage.Bind(service, item.Id);

                            mm.id = mes.Id.UniqueId;
                            mm.subject = mes.Subject;
                            mm.body = mes.Body;

                            if (mes.From != null)
                                mm.from = mes.From.Name;
                            foreach (var eaItem in mes.ToRecipients)
                            {
                                mm.to += eaItem.Name + ";";
                            }

                            if (mes.From != null)
                                mm.fromEmail = mes.From.Address;
                            foreach (var eaItem in mes.ToRecipients)
                            {
                                mm.to += eaItem.Address + ";";
                            }

                            mm.dateSent = mes.DateTimeSent;
                            mm.dateRecieved = mes.DateTimeReceived;
                            mm.isRead = mes.IsRead;

                            mes.IsRead = true;
                            mes.Update(ConflictResolutionMode.AlwaysOverwrite);

                            mmList.Add(mm);
                        }
                        catch { }
                    }
                }
            }


            return mmList;
        }

        public List<MailMessage> MessageSearch(string userLogin, string body, string subject)
        {
            GetImpersonation(userLogin);
            List<MailMessage> mmList = new List<MailMessage>();
            List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
            if (!string.IsNullOrEmpty(body))
                searchFilterCollection.Add(new SearchFilter.ContainsSubstring(ItemSchema.Body, body));
            if (!string.IsNullOrEmpty(subject))
                searchFilterCollection.Add(new SearchFilter.ContainsSubstring(ItemSchema.Subject, subject));
            SearchFilter sFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchFilterCollection.ToArray());
            ItemView view = new ItemView(100);
            view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, ItemSchema.DateTimeReceived);
            view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);
            FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, sFilter, view);
            foreach (Item item in findResults.Items)
            {
                if (item is EmailMessage)
                {
                    MailMessage mm = new MailMessage();
                    EmailMessage mes = EmailMessage.Bind(service, item.Id);
                    mm.id = mes.Id.UniqueId;
                    mm.subject = mes.Subject;
                    mm.body = mes.Body;

                    if (mes.From != null)
                        mm.from = mes.From.Name;
                    foreach (var eaItem in mes.ToRecipients)
                    {
                        mm.to += eaItem.Name + ";";
                    }

                    if (mes.From != null)
                        mm.fromEmail = mes.From.Address;
                    foreach (var eaItem in mes.ToRecipients)
                    {
                        mm.to += eaItem.Address + ";";
                    }

                    mm.dateSent = mes.DateTimeSent;
                    mm.dateRecieved = mes.DateTimeReceived;
                    mm.isRead = mes.IsRead;

                    mes.IsRead = true;
                    mes.Update(ConflictResolutionMode.AlwaysOverwrite);

                    mmList.Add(mm);
                }
            }
            return mmList;
        }

        public List<MailMessage> MessageSearch(string userLogin, WellKnownFolderName folderName)
        {
            GetImpersonation(userLogin);
            List<MailMessage> mmList = new List<MailMessage>();
            ItemView view = new ItemView(100);
            view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, ItemSchema.DateTimeReceived);
            view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);
            FindItemsResults<Item> findResults = service.FindItems(folderName, view);
            foreach (Item item in findResults.Items)
            {
                if (item is EmailMessage)
                {
                    MailMessage mm = new MailMessage();
                    EmailMessage mes = EmailMessage.Bind(service, item.Id);
                    mm.id = mes.Id.UniqueId;
                    mm.subject = mes.Subject;
                    mm.body = mes.Body;

                    if (mes.From != null)
                        mm.from = mes.From.Name;
                    foreach (var eaItem in mes.ToRecipients)
                    {
                        mm.to += eaItem.Name + ";";
                    }

                    if (mes.From != null)
                        mm.fromEmail = mes.From.Address;
                    foreach (var eaItem in mes.ToRecipients)
                    {
                        mm.to += eaItem.Address + ";";
                    }

                    if (mes.DateTimeSent != null)
                        mm.dateSent = mes.DateTimeSent;

                    if (mes.DateTimeReceived != null)
                    mm.dateRecieved = mes.DateTimeReceived;

                    mm.isRead = mes.IsRead;

                    mes.IsRead = true;
                    mes.Update(ConflictResolutionMode.AlwaysOverwrite);

                    mmList.Add(mm);
                }
            }
            return mmList;
        }

        public List<MailMessage> MessageSearch(string userLogin, string folderNames, int status, int details, int maxMailCount, int offset)
        {
            GetImpersonation(userLogin);
            List<MailMessage> mmList = new List<MailMessage>();

            ExtendedPropertyDefinition PR_Flags = new ExtendedPropertyDefinition(4240, MapiPropertyType.Integer);
            ExtendedPropertyDefinition PR_FlagRequest = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Common, 34096, MapiPropertyType.String);

            List<SearchFilter> searchFilterCollection = new List<SearchFilter>();

            if (status == 1 || status == 3)
                searchFilterCollection.Add(new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));

            if (status == 2 || status == 3)
                searchFilterCollection.Add(new SearchFilter.IsEqualTo(PR_Flags, "2"));

            ItemView view = new ItemView(maxMailCount, offset);
            view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties) { PR_Flags, PR_FlagRequest };


            foreach (string folderName in folderNames.Split(','))
            {
                string normFolderName = folderName.Trim();
                Microsoft.Exchange.WebServices.Data.Folder inbox;

                if (ConvertToWKFN(normFolderName) == WellKnownFolderName.Root)
                    inbox = Microsoft.Exchange.WebServices.Data.Folder.Bind(service, GetFoldersByNames(new List<string>() { normFolderName })[0].Id);
                else
                    inbox = Microsoft.Exchange.WebServices.Data.Folder.Bind(service, ConvertToWKFN(normFolderName));

                FindItemsResults<Item> findResults = null;

                if (status != 0)
                    findResults = inbox.FindItems(new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchFilterCollection.ToArray()), view);
                else
                    findResults = inbox.FindItems(view);

                foreach (Item item in findResults.Items)
                {
                    if (item is EmailMessage)
                    {
                        MailMessage mm = new MailMessage();
                        EmailMessage mes = EmailMessage.Bind(service, item.Id);

                        mm.id = mes.Id.UniqueId;
                        mm.subject = mes.Subject;

                        if (details == -1)
                            mm.body = mes.Body;
                        else if (details != 0)
                        {
                            if (mes.Body.Text.Length <= details)
                                mm.body = mes.Body;
                            else
                            {
                                mm.body = mes.Body;
                                mm.body.Text = mm.body.Text.Substring(0, details);
                            }
                        }

                        if (mes.From != null)
                            mm.from = mes.From.Name;

                        foreach (var eaItem in mes.ToRecipients)
                        {
                            mm.to += eaItem.Name + ";";
                        }

                        if (mes.From != null)
                            mm.fromEmail = mes.From.Address;

                        foreach (var eaItem in mes.ToRecipients)
                        {
                            mm.to += eaItem.Address + ";";
                        }

                        mm.dateSent = mes.DateTimeSent;
                        mm.dateRecieved = mes.DateTimeReceived;
                        mm.isRead = mes.IsRead;

                        mes.IsRead = true;
                        mes.Update(ConflictResolutionMode.AlwaysOverwrite);

                        mmList.Add(mm);
                    }
                }
            }
            return mmList;
        }

        public List<UserMails> GetMailsForMultipleUsers(List<string> usersLiveIDs, string subject, string body)
        {
            List<UserMails> uML = new List<UserMails>();
            foreach (string item in usersLiveIDs)
            {

                UserMails um = new UserMails();
                um.userLID = item;
                um.mails = MessageSearch(item, body, subject);
                uML.Add(um);
            }
            return uML;
        }

        public List<UserMails> GetMailsForMultipleUsers(List<string> usersLiveIDs, List<MailSearchParameter> parameters)
        {
            List<UserMails> uML = new List<UserMails>();
            foreach (string item in usersLiveIDs)
            {
                UserMails um = new UserMails();
                um.userLID = item;
                um.mails = MessageSearch(item, parameters, new List<string>());
                uML.Add(um);
            }
            return uML;
        }

        public void CreateAndSendMessage(string userLogin, string subject, string body, List<string> recipientsEMails, List<MailAttachment> lstAttachments)
        {
            GetImpersonation(userLogin);
            EmailMessage mes = new EmailMessage(service);
            mes.Subject = subject;
            mes.Body = body;

            foreach (var item in lstAttachments)
            {
                mes.Attachments.AddFileAttachment(item.filename, item.content);
            }

            foreach (string item in recipientsEMails)
            {
                mes.ToRecipients.Add(item);
            }

            mes.SendAndSaveCopy();
        }

        public string CreateDraftMessage(string userLogin, string subject, string body, List<string> recipientsEMails)
        {
            GetImpersonation(userLogin);
            EmailMessage mes = new EmailMessage(service);
            mes.Subject = subject;
            mes.Body = body;
            foreach (string item in recipientsEMails)
            {
                mes.ToRecipients.Add(item);
            }
            mes.Save(WellKnownFolderName.Drafts);

            return string.Format("https://{0}/owa/{1}&exsvurl=1",
                CurrnetServerUrl,
                EmailMessage.Bind(service, mes.Id).WebClientEditFormQueryString);
        }

        public string GetMailUrlById(string userLogin, string MailMessageID, bool IsReadOnly)
        {
            GetImpersonation(userLogin);
            EmailMessage mes = EmailMessage.Bind(service, new ItemId(MailMessageID));

            string tmp = string.Format("https://{0}/owa/{1}&exsvurl=1",
                CurrnetServerUrl,
                (IsReadOnly) ? mes.WebClientReadFormQueryString : mes.WebClientEditFormQueryString);

            return tmp;
        }

        public void DeleteMessage(string userLogin, string id, bool hardDelete)
        {
            GetImpersonation(userLogin);
            EmailMessage mes = EmailMessage.Bind(service, new ItemId(id));
            if (hardDelete == true)
                mes.Delete(DeleteMode.HardDelete);
            else
                mes.Delete(DeleteMode.MoveToDeletedItems);
        }
        #endregion

        #region Appointments
        public string CreateDraftAppointment(string userLogin, string subject, string body, string location, DateTime startDate, DateTime endDate)
        {
            GetImpersonation(userLogin);

            Microsoft.Exchange.WebServices.Data.Appointment app = new Microsoft.Exchange.WebServices.Data.Appointment(service);
            app.Subject = subject;
            app.Body = body;
            app.Start = startDate;
            app.End = endDate;
            app.Location = location;

            app.Save(WellKnownFolderName.Calendar, SendInvitationsMode.SendToNone);

            return string.Format("https://{0}/owa/{1}&exsvurl=1",
                CurrnetServerUrl,
                Microsoft.Exchange.WebServices.Data.Appointment.Bind(service, app.Id).WebClientEditFormQueryString);
        }

        public void CreateAppointment(string userLogin, string subject, string body, string location, DateTime startDate, DateTime endDate)
        {
            GetImpersonation(userLogin);
            Microsoft.Exchange.WebServices.Data.Appointment app = new Microsoft.Exchange.WebServices.Data.Appointment(service);
            app.Subject = subject;
            app.Body = body;
            app.Start = startDate;
            app.End = endDate;
            app.Location = location;
            app.Save(SendInvitationsMode.SendToNone);
        }

        public void DeleteAppointment(string userLogin, string id, bool hardDelete)
        {
            GetImpersonation(userLogin);
            Microsoft.Exchange.WebServices.Data.Appointment app = Microsoft.Exchange.WebServices.Data.Appointment.Bind(service, new ItemId(id));
            if (hardDelete == true)
                app.Delete(DeleteMode.HardDelete);
            else app.Delete(DeleteMode.MoveToDeletedItems);
        }

        public LiveWebServiceBase.ReturnedTypes.Appointment GetAppointmentContent(string userLogin, string id)
        {
            GetImpersonation(userLogin);
            LiveWebServiceBase.ReturnedTypes.Appointment appStruct = new LiveWebServiceBase.ReturnedTypes.Appointment();
            Microsoft.Exchange.WebServices.Data.Appointment appItem = Microsoft.Exchange.WebServices.Data.Appointment.Bind(service, new ItemId(id), new PropertySet(AppointmentSchema.IsAllDayEvent));
            appStruct.id = id;
            appStruct.subject = appItem.Subject;
            appStruct.body = appItem.Body;
            appStruct.startDate = appItem.Start;
            appStruct.endDate = appItem.End;
            appStruct.IsRecurring = (appItem.AppointmentType == AppointmentType.Occurrence);
            appStruct.IsAllDayEvent = appItem.IsAllDayEvent;
            appStruct.location = appItem.Location;
            return appStruct;
        }

        public List<LiveWebServiceBase.ReturnedTypes.Appointment> GetAppointments(string userLogin, DateTime startDate, DateTime endDate, string folderName)
        {
            GetImpersonation(userLogin);
            List<LiveWebServiceBase.ReturnedTypes.Appointment> appList = new List<LiveWebServiceBase.ReturnedTypes.Appointment>();
            CalendarView calView = new CalendarView(startDate, endDate);
            calView.PropertySet = new PropertySet(BasePropertySet.IdOnly, AppointmentSchema.Subject,
                AppointmentSchema.Start, AppointmentSchema.End, AppointmentSchema.Location, AppointmentSchema.AppointmentType, AppointmentSchema.IsAllDayEvent);

            FindItemsResults<Microsoft.Exchange.WebServices.Data.Appointment> findResults;

            if (folderName == string.Empty)
            {
                findResults = service.FindAppointments(WellKnownFolderName.Calendar, calView);
            }
            else
            {
                var result = FindFolder(userLogin, folderName).FirstOrDefault();

                if (result == null)
                    findResults = service.FindAppointments(WellKnownFolderName.Calendar, calView);
                else
                    findResults = service.FindAppointments(new FolderId(result.Id), calView);
            }

            foreach (Microsoft.Exchange.WebServices.Data.Appointment appt in findResults.Items)
            {
                if (appt.AppointmentType == AppointmentType.Occurrence || appt.AppointmentType == AppointmentType.Single)
                {
                    LiveWebServiceBase.ReturnedTypes.Appointment appStruct = new LiveWebServiceBase.ReturnedTypes.Appointment();

                    appStruct.id = appt.Id.UniqueId;
                    appStruct.subject = appt.Subject;
                    appStruct.startDate = appt.Start;
                    appStruct.endDate = appt.End;
                    appStruct.location = appt.Location;
                    appStruct.IsRecurring = (appt.AppointmentType == AppointmentType.Occurrence);
                    appStruct.IsAllDayEvent = appt.IsAllDayEvent;
                    appList.Add(appStruct);
                }
            }

            return appList;
        }

        public List<LiveWebServiceBase.ReturnedTypes.Appointment> GetNextAppointments(string userLogin, DateTime searchToDate)
        {
            GetImpersonation(userLogin);
            List<LiveWebServiceBase.ReturnedTypes.Appointment> appList = new List<LiveWebServiceBase.ReturnedTypes.Appointment>();
            List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
            searchFilterCollection.Add(new SearchFilter.IsLessThanOrEqualTo(AppointmentSchema.Start, searchToDate));
            searchFilterCollection.Add(new SearchFilter.IsGreaterThanOrEqualTo(AppointmentSchema.Start, DateTime.Now));
            SearchFilter sFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, searchFilterCollection.ToArray());
            ItemView view = new ItemView(100);
            view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, ItemSchema.DateTimeReceived);
            view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);
            FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Calendar, sFilter, view);
            foreach (Item item in findResults.Items)
            {
                if (item is Microsoft.Exchange.WebServices.Data.Appointment)
                {
                    LiveWebServiceBase.ReturnedTypes.Appointment appStruct = new LiveWebServiceBase.ReturnedTypes.Appointment();
                    Microsoft.Exchange.WebServices.Data.Appointment app = Microsoft.Exchange.WebServices.Data.Appointment.Bind(service, item.Id, new PropertySet(AppointmentSchema.IsAllDayEvent));
                    appStruct.id = item.Id.UniqueId;
                    appStruct.subject = app.Subject;
                    appStruct.body = app.Body;
                    appStruct.startDate = app.Start;
                    appStruct.endDate = app.End;
                    appStruct.location = app.Location;
                    appStruct.IsRecurring = (app.AppointmentType == AppointmentType.Occurrence);
                    appStruct.IsAllDayEvent = app.IsAllDayEvent;
                    appList.Add(appStruct);
                }
            }
            return appList;
        }

        public List<UserAppointments> GetAppointmentsForMultipleUser(List<string> usersLiveIDs, DateTime period)
        {
            List<UserAppointments> usL = new List<UserAppointments>();
            foreach (string item in usersLiveIDs)
            {
                UserAppointments apps = new UserAppointments();
                apps.userLID = item;
                apps.appointments = GetNextAppointments(item, period);
                usL.Add(apps);
            }
            return usL;
        }

        public string GetAppointmentUrlById(string userLogin, string AppointmentID, bool IsReadOnly)
        {
            GetImpersonation(userLogin);
            Microsoft.Exchange.WebServices.Data.Appointment appItem = Microsoft.Exchange.WebServices.Data.Appointment.Bind(service, new ItemId(AppointmentID), new PropertySet(AppointmentSchema.IsAllDayEvent, AppointmentSchema.WebClientEditFormQueryString, AppointmentSchema.WebClientReadFormQueryString));

            return string.Format("https://{0}/owa/{1}&exsvurl=1",
                CurrnetServerUrl,
                (IsReadOnly) ? appItem.WebClientReadFormQueryString : appItem.WebClientEditFormQueryString);
        }

        #endregion

        #region Contacts

        public void CreateContact(string userLogin, Dictionary<ContactParameterType, object> parametrs)
        {
            EditContact(userLogin, null, parametrs);
        }

        public void EditContact(string userLogin, String contactID, Dictionary<ContactParameterType, object> parametrs)
        {
            GetImpersonation(userLogin);
            Microsoft.Exchange.WebServices.Data.Contact contact;

            if (contactID != null)
                contact = Microsoft.Exchange.WebServices.Data.Contact.Bind(service, new ItemId(contactID));
            else
                contact = new Microsoft.Exchange.WebServices.Data.Contact(service);

            foreach (var item in parametrs)
            {
                #region EmailAddress
                if (item.Key.ToString().Contains("EmailAddress"))
                {
                    EmailAddressKey emailKey;

                    switch (item.Key.ToString().Remove(12, item.Key.ToString().Length - 12))
                    {
                        case "EmailAddress1":
                            emailKey = EmailAddressKey.EmailAddress1;
                            break;
                        case "EmailAddress2":
                            emailKey = EmailAddressKey.EmailAddress2;
                            break;
                        case "EmailAddress3":
                            emailKey = EmailAddressKey.EmailAddress3;
                            break;
                        default:
                            emailKey = EmailAddressKey.EmailAddress1;
                            break;
                    }

                    EmailAddress email = new EmailAddress();
                    email.Address = (item.Value as LiveWebServiceBase.ReturnedTypes.EmailAddressEntry).Address;
                    email.MailboxType = (item.Value as LiveWebServiceBase.ReturnedTypes.EmailAddressEntry).MailboxType;
                    email.Name = (item.Value as LiveWebServiceBase.ReturnedTypes.EmailAddressEntry).Name;
                    email.RoutingType = (item.Value as LiveWebServiceBase.ReturnedTypes.EmailAddressEntry).RoutingType;

                    contact.EmailAddresses[emailKey] = email;
                }
                #endregion

                #region ImAddress
                else if (item.Key.ToString().Contains("ImAddress"))
                {
                    ImAddressKey imKey;

                    switch (item.Key.ToString())
                    {
                        case "ImAddress1":
                            imKey = ImAddressKey.ImAddress1;
                            break;
                        case "ImAddress2":
                            imKey = ImAddressKey.ImAddress2;
                            break;
                        case "ImAddress3":
                            imKey = ImAddressKey.ImAddress3;
                            break;
                        default:
                            imKey = ImAddressKey.ImAddress1;
                            break;
                    }

                    contact.ImAddresses[imKey] = item.Value.ToString();
                }
                #endregion

                #region PhoneNumber
                else if (item.Key.ToString().Contains("PhoneNumber"))
                {
                    PhoneNumberKey phoneKey;

                    switch (item.Key.ToString().Remove(0, 11))
                    {
                        case "AssistantPhone":
                            phoneKey = PhoneNumberKey.AssistantPhone;
                            break;
                        case "BusinessFax":
                            phoneKey = PhoneNumberKey.BusinessFax;
                            break;
                        case "BusinessPhone":
                            phoneKey = PhoneNumberKey.BusinessPhone;
                            break;
                        case "BusinessPhone2":
                            phoneKey = PhoneNumberKey.BusinessPhone2;
                            break;
                        case "Callback":
                            phoneKey = PhoneNumberKey.Callback;
                            break;
                        case "CarPhone":
                            phoneKey = PhoneNumberKey.CarPhone;
                            break;
                        case "CompanyMainPhone":
                            phoneKey = PhoneNumberKey.CompanyMainPhone;
                            break;
                        case "HomeFax":
                            phoneKey = PhoneNumberKey.HomeFax;
                            break;
                        case "HomePhone":
                            phoneKey = PhoneNumberKey.HomePhone;
                            break;
                        case "HomePhone2":
                            phoneKey = PhoneNumberKey.HomePhone2;
                            break;
                        case "Isdn":
                            phoneKey = PhoneNumberKey.Isdn;
                            break;
                        case "MobilePhone":
                            phoneKey = PhoneNumberKey.MobilePhone;
                            break;
                        case "OtherFax":
                            phoneKey = PhoneNumberKey.OtherFax;
                            break;
                        case "OtherTelephone":
                            phoneKey = PhoneNumberKey.OtherTelephone;
                            break;
                        case "Pager":
                            phoneKey = PhoneNumberKey.Pager;
                            break;
                        case "PrimaryPhone":
                            phoneKey = PhoneNumberKey.PrimaryPhone;
                            break;
                        case "RadioPhone":
                            phoneKey = PhoneNumberKey.RadioPhone;
                            break;
                        case "Telex":
                            phoneKey = PhoneNumberKey.Telex;
                            break;
                        case "TtyTddPhone":
                            phoneKey = PhoneNumberKey.TtyTddPhone;
                            break;
                        default:
                            phoneKey = PhoneNumberKey.MobilePhone;
                            break;
                    }

                    contact.PhoneNumbers[phoneKey] = item.Value.ToString();
                }
                #endregion

                #region PhysicalAddresses
                else if (item.Key.ToString().Contains("PhysicalAddresses"))
                {
                    PhysicalAddressKey addressKey;

                    switch (item.Key.ToString().Remove(0, 17))
                    {
                        case "Business":
                            addressKey = PhysicalAddressKey.Business;
                            break;
                        case "Home":
                            addressKey = PhysicalAddressKey.Home;
                            break;
                        case "Other":
                            addressKey = PhysicalAddressKey.Other;
                            break;
                        default:
                            addressKey = PhysicalAddressKey.Other;
                            break;
                    }

                    Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry address = new Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry();
                    address.City = (item.Value as LiveWebServiceBase.ReturnedTypes.PhysicalAddressEntry).City;
                    address.CountryOrRegion = (item.Value as LiveWebServiceBase.ReturnedTypes.PhysicalAddressEntry).CountryOrRegion;
                    address.PostalCode = (item.Value as LiveWebServiceBase.ReturnedTypes.PhysicalAddressEntry).PostalCode;
                    address.State = (item.Value as LiveWebServiceBase.ReturnedTypes.PhysicalAddressEntry).State;
                    address.Street = (item.Value as LiveWebServiceBase.ReturnedTypes.PhysicalAddressEntry).Street;

                    contact.PhysicalAddresses[addressKey] = address;
                }

                #endregion

                #region Children & Companies
                else if (item.Key.ToString() == "Companies" || item.Key.ToString() == "Children")
                {
                    switch (item.Key.ToString())
                    {
                        case "Children":
                            contact.Children = (StringList)item.Value;
                            break;
                        case "Companies":
                            contact.Companies = (StringList)item.Value;
                            break;
                        default:
                            break;
                    }
                }
                #endregion

                #region Others
                else
                {
                    Type propertyType;
                    if (contact.GetType().GetProperty(item.Key.ToString()).PropertyType.ToString().Contains("DateTime"))
                        propertyType = contact.GetType().GetProperty(item.Key.ToString()).PropertyType.GetGenericArguments()[0];
                    else
                        propertyType = contact.GetType().GetProperty(item.Key.ToString()).PropertyType;

                    contact.GetType().GetProperty(item.Key.ToString()).SetValue(contact, Convert.ChangeType(item.Value, propertyType), null);
                }
                #endregion
            }

            if (contactID != null)
                contact.Update(ConflictResolutionMode.AlwaysOverwrite);
            else
                contact.Save();
        }

        public void DeleteContact(string userLogin, string contactID)
        {
            GetImpersonation(userLogin);
            Microsoft.Exchange.WebServices.Data.Contact contact = Microsoft.Exchange.WebServices.Data.Contact.Bind(service, new ItemId(contactID));
            contact.Delete(DeleteMode.MoveToDeletedItems);
        }

        public LiveWebServiceBase.ReturnedTypes.Contact GetContact(string userLogin, string contactID)
        {
            GetImpersonation(userLogin);
            LiveWebServiceBase.ReturnedTypes.Contact retValue = new LiveWebServiceBase.ReturnedTypes.Contact();

            Microsoft.Exchange.WebServices.Data.Contact contact = Microsoft.Exchange.WebServices.Data.Contact.Bind(service, contactID);

            if (contact != null)
                return ConvertContact(contact);
            else
                return null;
        }

        public LiveWebServiceBase.ReturnedTypes.Contact[] GetContact(string userLogin, WellKnownFolderName Folder, Dictionary<ContactParameterType, object> parametrs)
        {
            GetImpersonation(userLogin);
            List<LiveWebServiceBase.ReturnedTypes.Contact> retval = new List<LiveWebServiceBase.ReturnedTypes.Contact>();

            //GetImpersonation(userLogin);
            List<SearchFilter> searchFilterCollection = new List<SearchFilter>();

            foreach (var item in parametrs)
                searchFilterCollection.Add(new SearchFilter.IsEqualTo(GetItemSchema(item.Key), item.Value));

            SearchFilter sFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, searchFilterCollection.ToArray());
            ItemView view = new ItemView(100);
            view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
            view.OrderBy.Add(ItemSchema.ItemClass, SortDirection.Descending);
            FindItemsResults<Item> findResults = service.FindItems(Folder, sFilter, view);
            foreach (Item item in findResults.Items)
                if (item is Microsoft.Exchange.WebServices.Data.Contact)
                    retval.Add(GetContact(userLogin, item.Id.UniqueId));

            return retval.ToArray();
        }

        public LiveWebServiceBase.ReturnedTypes.Contact[] GetContact(string userLogin, string FolderID, Dictionary<ContactParameterType, object> parametrs)
        {
            GetImpersonation(userLogin);
            List<LiveWebServiceBase.ReturnedTypes.Contact> retval = new List<LiveWebServiceBase.ReturnedTypes.Contact>();

            //GetImpersonation(userLogin);
            List<SearchFilter> searchFilterCollection = new List<SearchFilter>();

            foreach (var item in parametrs)
                searchFilterCollection.Add(new SearchFilter.IsEqualTo(GetItemSchema(item.Key), item.Value));

            SearchFilter sFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, searchFilterCollection.ToArray());
            ItemView view = new ItemView(100);
            view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
            view.OrderBy.Add(ItemSchema.ItemClass, SortDirection.Descending);
            FindItemsResults<Item> findResults = service.FindItems(new FolderId(FolderID), sFilter, view);
            foreach (Item item in findResults.Items)
                if (item is Microsoft.Exchange.WebServices.Data.Contact)
                    retval.Add(GetContact(userLogin, item.Id.UniqueId));

            return retval.ToArray();
        }

        #endregion

        #region Folders

        #region Create Folder
        public void CreateFolder(string userLogin, WellKnownFolderName parentFolderType, Dictionary<FolderParameterType, object> parametrs)
        {
            GetImpersonation(userLogin);
            Microsoft.Exchange.WebServices.Data.Folder folder = new Microsoft.Exchange.WebServices.Data.Folder(service);

            foreach (var item in parametrs)
            {
                Type type = folder.GetType().GetProperty(item.Key.ToString()).PropertyType;
                folder.GetType().GetProperty(item.Key.ToString()).SetValue(folder, Convert.ChangeType(item.Value, type), null);
            }

            folder.Save(parentFolderType);
        }

        public void CreateFolder(string userLogin, String parentFolderID, Dictionary<FolderParameterType, object> parametrs)
        {
            GetImpersonation(userLogin);
            Microsoft.Exchange.WebServices.Data.Folder folder = new Microsoft.Exchange.WebServices.Data.Folder(service);

            foreach (var item in parametrs)
            {
                Type type = folder.GetType().GetProperty(item.Key.ToString()).PropertyType;
                folder.GetType().GetProperty(item.Key.ToString()).SetValue(folder, Convert.ChangeType(item.Value, type), null);
            }

            folder.Save(parentFolderID);
        }
        #endregion

        #region UpdateFolder

        public void UpdateFolder(string userLogin, string folderId, Dictionary<FolderParameterType, object> parametrs)
        {
            GetImpersonation(userLogin);
            Microsoft.Exchange.WebServices.Data.Folder folder = Microsoft.Exchange.WebServices.Data.Folder.Bind(service, folderId);

            foreach (var item in parametrs)
            {
                Type type = folder.GetType().GetProperty(item.Key.ToString()).PropertyType;
                folder.GetType().GetProperty(item.Key.ToString()).SetValue(folder, Convert.ChangeType(item.Value, type), null);
            }

            folder.Update();
        }

        #endregion

        #region Delete Folder
        public void DeleteFolder(string userLogin, string folderId)
        {
            GetImpersonation(userLogin);

            Microsoft.Exchange.WebServices.Data.Folder folder = Microsoft.Exchange.WebServices.Data.Folder.Bind(service, folderId);
            folder.Delete(DeleteMode.HardDelete);
        }
        #endregion

        #region Get Folder

        public LiveWebServiceBase.ReturnedTypes.Folder GetFolder(string userLogin, string folderID)
        {
            GetImpersonation(userLogin);
            return ConvertFolder(Microsoft.Exchange.WebServices.Data.Folder.Bind(service, folderID));
        }

        public LiveWebServiceBase.ReturnedTypes.Folder[] GetFolder(string userLogin, Dictionary<FolderSearchParameterType, object> parametrs)
        {
            return GetFolder(userLogin, WellKnownFolderName.Root, parametrs);
        }

        public LiveWebServiceBase.ReturnedTypes.Folder[] GetFolder(string userLogin, string parentFolderID, Dictionary<FolderSearchParameterType, object> parametrs)
        {
            GetImpersonation(userLogin);

            List<LiveWebServiceBase.ReturnedTypes.Folder> retval = new List<LiveWebServiceBase.ReturnedTypes.Folder>();

            FolderView view = new FolderView(100);
            view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
            view.PropertySet.Add(FolderSchema.DisplayName);
            view.Traversal = FolderTraversal.Deep;

            List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
            foreach (var item in parametrs)
                searchFilterCollection.Add(new SearchFilter.IsEqualTo(GetItemSchema(item.Key), item.Value));
            SearchFilter sFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, searchFilterCollection.ToArray());

            FindFoldersResults findFolderResults;

            if (parametrs.Count > 0)
                findFolderResults = service.FindFolders(new FolderId(parentFolderID), sFilter, view);
            else
                findFolderResults = service.FindFolders(new FolderId(parentFolderID), view);

            foreach (var item in findFolderResults)
                if (!(item is Microsoft.Exchange.WebServices.Data.SearchFolder))
                    try
                    {
                        retval.Add(GetFolder(userLogin, item.Id.UniqueId));
                    }
                    catch { }


            return retval.ToArray();
        }

        public LiveWebServiceBase.ReturnedTypes.Folder[] GetFolder(string userLogin, WellKnownFolderName parentFolderType, Dictionary<FolderSearchParameterType, object> parametrs)
        {
            GetImpersonation(userLogin);

            List<LiveWebServiceBase.ReturnedTypes.Folder> retval = new List<LiveWebServiceBase.ReturnedTypes.Folder>();

            FolderView view = new FolderView(100);
            view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
            view.PropertySet.Add(FolderSchema.DisplayName);
            view.Traversal = FolderTraversal.Deep;

            List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
            foreach (var item in parametrs)
                searchFilterCollection.Add(new SearchFilter.IsEqualTo(GetItemSchema(item.Key), item.Value));
            SearchFilter sFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, searchFilterCollection.ToArray());

            FindFoldersResults findFolderResults;

            if (parametrs.Count > 0)
                findFolderResults = service.FindFolders(parentFolderType, sFilter, view);
            else
                findFolderResults = service.FindFolders(parentFolderType, view);

            foreach (var item in findFolderResults)
                if (!(item is Microsoft.Exchange.WebServices.Data.SearchFolder))
                    try
                    {
                        retval.Add(GetFolder(userLogin, item.Id.UniqueId));
                    }
                    catch { }

            return retval.ToArray();
        }

        #endregion

        #region Find Folder
        public LiveWebServiceBase.ReturnedTypes.Folder[] FindFolder(string userLogin, string folderName)
        {
            GetImpersonation(userLogin);

            List<LiveWebServiceBase.ReturnedTypes.Folder> retval = new List<LiveWebServiceBase.ReturnedTypes.Folder>();

            var foldersArray = new List<Microsoft.Exchange.WebServices.Data.Folder>();

            if (!string.IsNullOrEmpty(folderName.Trim(' ')))
                foldersArray = GetFoldersByNames(new List<string>() { folderName });
            else
                foldersArray = GetAllFolders();

            foreach (var item in foldersArray)
                if ((item is Microsoft.Exchange.WebServices.Data.Folder || item is CalendarFolder) && !(item is SearchFolder))
                {
                    retval.Add(ConvertFolder(item));
                }

            return retval.ToArray();
        }
        #endregion

        #endregion
    }
}
